#ifndef MSGHANDLER_INC
#define MSGHANDLER_INC

#include "MsgTypes.h"

class MsgHandler
{
public:
	MsgHandler( UInt8 worker_ = 0xFF )
		: _worker( worker_ )
	{
	}
	virtual ~MsgHandler()
	{
	}

public:
	 void DeregisterAllMsg();

	 bool ProcessMsg();

	 template <typename HdrType, typename StructType>
	 inline void RegisterMsgHandler( void (*handlerfunc)(HdrType&, StructType&) )
	 {
		 Handler *handler = new Handler();
		 ASSERT( handler != NULL );
		 handler->_func = (char*)handlerfunc;	//save function pointer
		 handler->_wrapper = &HandlerWrapper<HdrType, StructType>;
		 UInt32 msgId = StructType::s_MsgId;
		 Handler *& _handler = _handlerList[msgId];
		 ASSERT( _handler == nullptr );
		 _handler = handler;
	 }

	 template <typename HdrType, int MsgId, typename StructType>
	 inline void RegisterMsgHandler( void (*handlerfunc)(HdrType&, StructType *) )
	 {
		 Handler *handler = new Handler();
		 ASSERT( handler != nullptr );
		 handler->_func = (char*)handlerfunc;	//save function pointer
		 handler->_wrapper = &HandlerWrapper2<HdrType, StructType>;
		 Handler *& _handler = _handlerList[MsgId];
		 ASSERT( _handler == nullptr );
		 _handler = handler;
	 }

protected:
	template <typename HdrType, typename StructType>
	static bool HandlerWrapper(char* func, const MsgHdr* hdr)
	{
		StructType msg1;
		char* msgBody = (char*)((HdrType*)hdr + 1);

		if(msg1.Unserialize( msgBody, ((HdrType*)hdr)->_len ) != static_cast<UInt32>(-1))
			((void (*)(HdrType&, StructType&))func)(*(HdrType*)hdr, msg1);
		return true;
	}

	 template <typename HdrType, typename StructType>
	 static bool HandlerWrapper2(char* func, const MsgHdr* hdr)
	 {
		 StructType* msgBody = (StructType *)((HdrType*)hdr + 1);

		 return ((bool (*)(HdrType&, StructType *))func)(*(HdrType*)hdr, msgBody);
	 }

private:
	 struct Handler
	 {
		 bool (*_wrapper)(char*, const MsgHdr*);
		 char * _func;
	 };

	 UInt8	_worker;
	 std::unordered_map<UInt32, Handler *> _handlerList;
};

#define MSG_HANDLER_DEFINE(cls)	\
class cls : public MsgHandler	\
{	\
public:	\
	cls(UInt8 worker_ = 0xFF);	\
};	\

#define MSG_HANDLER_DECLARE(cls)	\
	cls::cls( UInt8 worker ) : MsgHandler( worker )	\
{	\

#define MSG_HANDLER_END()	\
}	\

#define MSG_REG_2(H, T, F) \
	RegisterMsgHandler<H, T, const void>(&F)

#define MSG_REG(H, F) \
	RegisterMsgHandler<H>(&F)

#endif
